package smarthouse;

import java.lang.reflect.Field;
import java.util.Hashtable;
import java.util.LinkedList;
import java.util.Vector;

import commands.CommandInterface;

import annotations.Command;
import annotations.Param;

import devices.AbstractDevice;
import devices.Heater;
import devices.Light;
import fakeSmarthouseHW.FakeSmarthouse;

public class Smarthouse {
	
	Vector<AbstractDevice> devices =  new Vector<AbstractDevice>();
	private static Smarthouse instance = new Smarthouse();
	
	
	private Smarthouse(){
		
		devices.add(new Heater(1, Room.BEDROOM));
		devices.add(new Heater(2, Room.LIVINGROOM));
		devices.add(new Light(3, Room.BEDROOM));
		devices.add(new Heater(4, Room.KITCHEN));
		devices.add(new Light(5, Room.LIVINGROOM));
		devices.add(new Light(6, Room.LIVINGROOM));
		devices.add(new Light(7, Room.KITCHEN));
		
		Vector<Vector<AbstractDevice>> devicesByRoom = getDevicesByRoom();
		
		SmarthouseXMLEnc enc = new SmarthouseXMLEnc();
		String xml = enc.encode(devicesByRoom);
		System.out.println(xml);
		
		
	/*	devices.add(new Heater(1, Room.BEDROOM));
		devices.add(new Heater(2, Room.BEDROOM));
		devices.add(new Light(3, Room.BEDROOM));
		devices.add(new Heater(4, Room.BEDROOM));
		devices.add(new Light(5, Room.BEDROOM));
		devices.add(new Light(6, Room.BEDROOM));
		devices.add(new Light(7, Room.BEDROOM));*/

	}
	
	public Vector<Vector<AbstractDevice>> getDevicesByRoom(){
		Vector<Vector<AbstractDevice>> devicesByRoom = new Vector<Vector<AbstractDevice>>();
		Room[] rooms = Room.values();
		for (int i = 0; i < rooms.length; i++) {
			Vector<AbstractDevice> devicesInRoom = new Vector<AbstractDevice>();
			devicesByRoom.add(devicesInRoom);
			
			int size = devices.size();
			for (int j=0;j<size;j++) {
				AbstractDevice device = devices.get(j);
				if (device.getRoom().equals(rooms[i]))
					devicesInRoom.add(device);
			}
			
		}
		
		return devicesByRoom;
	}
	
	
	
	public static Smarthouse getInstance(){
		return instance;
	}
	
	public Hashtable<Integer,Object> getDeviceData(AbstractDevice targetDevice){
		int deviceId = targetDevice.getId();
		LinkedList<Object> data = FakeSmarthouse.getInstance().fetchDeviceState(deviceId);
		
		Hashtable<Integer, Object> deviceData = new Hashtable<Integer, Object>();
		
		int i=0;
		while (!data.isEmpty()){
			deviceData.put(i, data.removeFirst());
			i++;
		}
		
		return deviceData;
	}
	
	public Hashtable<Integer,Object> getDeviceData(int deviceId){
		LinkedList<Object> data = FakeSmarthouse.getInstance().fetchDeviceState(deviceId);
		
		Hashtable<Integer, Object> deviceData = new Hashtable<Integer, Object>();
		
		int i=0;
		while (!data.isEmpty()){
			deviceData.put(i, data.removeFirst());
			i++;
		}
		
		return deviceData;
	}
	
	
	
	
	
	public Vector<AbstractDevice> getDevices(){
		return devices;
	}	
	
	/**
	 * This method should send commands to hardware interface, with parameters sorted by their id.
	 * @param device Device targeted by command
	 * @param command Command to be executed by the device
	 */
	public void sendCommand(AbstractDevice device, CommandInterface command){
		int deviceId = device.getId();
		sendCommand(deviceId, command);
	}
	/**
	 * This method should send commands to hardware interface, with parameters sorted by their id.
	 * @param deviceId ID of device targeted by command
	 * @param command Command to be executed by the device
	 */	
	public void sendCommand(int deviceId, CommandInterface command){
		
		int commandId = command.getClass().getAnnotation(Command.class).id();
		LinkedList<Object> params = new LinkedList<Object>();
		
		Hashtable<Integer, Object> tempParams = new Hashtable<Integer, Object>();
			
		Field[] fields = command.getClass().getDeclaredFields();
		
		for (Field field : fields) {
			field.setAccessible(true);
			if (!field.isAnnotationPresent(Param.class)) continue;
			Param param = field.getAnnotation(Param.class);
			try {
				tempParams.put(param.id(),field.get(command));
			} catch (Exception e) {
				e.printStackTrace();
			} 
		}
		
		int i=0;
		Object parameter;
		while(!tempParams.isEmpty()){
			parameter = tempParams.remove(i);
			if (parameter==null) {
				i++;
				continue;
			} else {
				params.addLast(parameter);
			}
		}
		System.out.println("SERVER: params"+params+"\nCOMMAND:"+commandId+"\n DEVICE:"+deviceId);
		FakeSmarthouse.getInstance().broadcastCommand(deviceId, commandId, params);
		
		
	}

}
